package com.julewa.db;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.julewa.loading.SpringLoader;

/*
 * 实现了Manager的如下几个关键方法
 * T get(key);
 * boolean insert(T);
 * boolean update(T);
 * boolean delete(T);
 * 
 * boolean update(id, param);
 * boolean delete(id, param);
 * 
 * List<T> select(id, param);
 * List<T> select(id, param, skip, max);
 * 
 */

@SuppressWarnings({"rawtypes", "unchecked"})
public final class Store<T> {
	private Class<T> clazz = null;
	private DB db = null;
	private Identifier idsrv = null;
	private Transaction trans = null;
	private String prefix = null;
	private String OBJECT = null;
	private String INSERT = null;
	private String UPDATE = null;
	private String DELETE = null;
	private String name = null;
	//
	private BeanInfo info = null;
	//
	private Map cache = null;
	public Store(Class<T> clazz){
		this.clazz = clazz;//SystemUtils.getTypeArgument(this.getClass());
		this.db = SpringLoader.getInstance(DB.class);
		this.trans = SpringLoader.getInstance(Transaction.class);
		this.idsrv = SpringLoader.getInstance(Identifier.class);
		//
		if(clazz.getAnnotation(DB.USECACHE.class) == null){
			return;
		}
		if(!Entity.class.isAssignableFrom(clazz)){
			return;
		}
		//先用这个吧
		//TODO 以后可以把这个改成memcache来做
		this.cache = Collections.synchronizedMap(new HashMap());
	}
	
	private void loadPrefix(){
		if(name != null)return;
		this.name = this.trans.getNamespace(clazz);
		if(this.name == null){
			name = "";
			prefix = "";
			return;
		}
		this.prefix = name + ".";
		this.OBJECT = this.prefix + "object";
		this.INSERT = this.prefix + "insert";
		this.UPDATE = this.prefix + "update";
		this.DELETE = this.prefix + "delete";
		//
		this.info = this.db.getBeanInfo(clazz);
	}
	public Class<T> getEntityClass(){
		return clazz;
	}
	
	public String getTypeName(){
		return name;
	}
	
	public Long generateID(){
		if(name == null)return null;
		if(idsrv == null)return null;
		return idsrv.generate(name);
	}
	
	public T get(Object id){
		loadPrefix();
		if(cache == null){
			return (T)db.getObject(OBJECT, id);
		}
		T t = (T)cache.get(id);
		if(t == null){
			t = (T)db.getObject(OBJECT, id);
			cache.put(id, t);
		}
		return t;
	}
	
	public T create(){
		return db.create(clazz);
	}
	
	public boolean insert(T ent){
		loadPrefix();
		if(cache == null){
			return db.insert(INSERT, ent);
		}else{
			if(db.insert(INSERT, ent)){
				cache.put(((Entity)ent).getID(), ent);
				return true;
			}else{
				return false;
			}
		}
	}
	public boolean update(T ent){
		loadPrefix();
		if(db.update(UPDATE, ent)){
			Object id = ((Entity)ent).getID();
			T old = (T)this.cache.get(id);
			if(old == ent)return true;
			if(old == null){
				this.cache.put(id, ent);
			}else{
				try {
					this.info.copy(ent, old);
				} catch (Exception e){
					e.printStackTrace();
					return false;
				}
			}
			return true;
		};
		return false;
	}
	public boolean update(String id, Object param){
		loadPrefix();
		if(cache != null){
			cache.clear();
		}
		return db.update(prefix + id, param);
	}
	public boolean delete(T ent){
		loadPrefix();
		if(db.delete(DELETE, ent)){
			if(cache != null){
				cache.remove(((Entity)ent).getID());
			}
			return true;
		}else{
			return false;
		}
	}
	public boolean delete(String id, Object param){
		loadPrefix();
		if(cache != null){
			cache.clear();
		}
		return db.delete(prefix + id, param);
	}
	private List<T> _cvt(List ls){
		if(cache == null){
			return (List<T>)ls;
		}
		List<T> ents = new ArrayList<T>();
		for(Object k:ls){
			ents.add(this.get(k));
		}
		return ents;
	}
	/////////////
	public List<T> select(String id, Object param){
		loadPrefix();
		return _cvt(db.getList(prefix + id, param));
	}
	public List<T> select(String id, Object param, int skip, int max){
		loadPrefix();
		return _cvt(db.getList(prefix + id, param, skip, max));
	}
}
